#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""项目管理模块"""

import os
import json
import shutil
import logging
from datetime import datetime


class ProjectManager:
    """项目管理类，负责项目的创建、打开、保存等操作"""
    
    # 项目配置文件名
    PROJECT_CONFIG_FILE = "project.json"
    
    # 默认项目结构
    DEFAULT_PROJECT_STRUCTURE = {
        "src": [],
        "resources": ["images", "icons", "sounds"],
        "docs": [],
        "tests": []
    }
    
    def __init__(self):
        """初始化项目管理器"""
        # 当前项目路径
        self.current_project_path = None
        
        # 当前项目配置
        self.current_project_config = None
        
        # 日志配置
        logging.basicConfig(
            level=logging.INFO,
            format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
        )
        self.logger = logging.getLogger("ProjectManager")
    
    def create_project(self, project_path, project_name, template="default"):
        """创建新项目
        
        Args:
            project_path: 项目路径
            project_name: 项目名称
            template: 项目模板类型
            
        Returns:
            bool: 是否创建成功
        """
        try:
            # 检查项目路径是否存在
            if not os.path.exists(project_path):
                os.makedirs(project_path)
            
            # 创建项目目录
            full_project_path = os.path.join(project_path, project_name)
            
            # 检查项目目录是否已存在
            if os.path.exists(full_project_path):
                self.logger.error(f"项目目录 '{full_project_path}' 已存在")
                return False, "项目目录已存在"
            
            # 创建项目主目录
            os.makedirs(full_project_path)
            
            # 创建项目结构
            self._create_project_structure(full_project_path)
            
            # 创建项目配置文件
            project_config = self._create_project_config(project_name, full_project_path)
            
            # 保存项目配置
            self._save_project_config(full_project_path, project_config)
            
            # 设置当前项目
            self.current_project_path = full_project_path
            self.current_project_config = project_config
            
            self.logger.info(f"项目 '{project_name}' 创建成功")
            return True, full_project_path
        except Exception as e:
            self.logger.error(f"创建项目失败: {str(e)}")
            return False, f"创建项目失败: {str(e)}"
    
    def open_project(self, project_path):
        """打开现有项目
        
        Args:
            project_path: 项目路径
            
        Returns:
            bool: 是否打开成功
        """
        try:
            # 检查项目路径是否存在
            if not os.path.exists(project_path):
                self.logger.error(f"项目路径 '{project_path}' 不存在")
                return False, "项目路径不存在"
            
            # 检查项目配置文件是否存在
            config_file_path = os.path.join(project_path, self.PROJECT_CONFIG_FILE)
            
            if not os.path.exists(config_file_path):
                # 如果没有项目配置文件，尝试将当前目录作为项目
                self.logger.warning(f"项目配置文件不存在，尝试将目录 '{project_path}' 作为项目打开")
                
                # 创建临时配置
                project_name = os.path.basename(project_path)
                project_config = self._create_project_config(project_name, project_path)
                
                # 设置当前项目
                self.current_project_path = project_path
                self.current_project_config = project_config
                
                return True, project_path
            
            # 加载项目配置
            project_config = self._load_project_config(config_file_path)
            
            # 设置当前项目
            self.current_project_path = project_path
            self.current_project_config = project_config
            
            self.logger.info(f"项目 '{project_config['name']}' 打开成功")
            return True, project_path
        except Exception as e:
            self.logger.error(f"打开项目失败: {str(e)}")
            return False, f"打开项目失败: {str(e)}"
    
    def save_project(self):
        """保存当前项目
        
        Returns:
            bool: 是否保存成功
        """
        try:
            # 检查是否有打开的项目
            if not self.current_project_path or not self.current_project_config:
                self.logger.error("没有打开的项目")
                return False, "没有打开的项目"
            
            # 更新项目修改时间
            self.current_project_config["last_modified"] = datetime.now().isoformat()
            
            # 保存项目配置
            self._save_project_config(self.current_project_path, self.current_project_config)
            
            self.logger.info(f"项目 '{self.current_project_config['name']}' 保存成功")
            return True, "保存成功"
        except Exception as e:
            self.logger.error(f"保存项目失败: {str(e)}")
            return False, f"保存项目失败: {str(e)}"
    
    def close_project(self):
        """关闭当前项目"""
        self.logger.info(f"项目 '{self.current_project_config['name'] if self.current_project_config else '未知'}' 已关闭")
        self.current_project_path = None
        self.current_project_config = None
    
    def get_current_project_path(self):
        """获取当前项目路径
        
        Returns:
            str: 当前项目路径
        """
        return self.current_project_path
    
    def get_current_project_config(self):
        """获取当前项目配置
        
        Returns:
            dict: 当前项目配置
        """
        return self.current_project_config
    
    def get_project_name(self):
        """获取当前项目名称
        
        Returns:
            str: 当前项目名称
        """
        if not self.current_project_config:
            return "无项目"
        return self.current_project_config.get("name", "无项目")
    
    def get_source_directory(self):
        """获取源代码目录
        
        Returns:
            str: 源代码目录路径
        """
        if not self.current_project_path:
            return None
        return os.path.join(self.current_project_path, "src")
    
    def get_resources_directory(self):
        """获取资源目录
        
        Returns:
            str: 资源目录路径
        """
        if not self.current_project_path:
            return None
        return os.path.join(self.current_project_path, "resources")
    
    def get_documents_directory(self):
        """获取文档目录
        
        Returns:
            str: 文档目录路径
        """
        if not self.current_project_path:
            return None
        return os.path.join(self.current_project_path, "docs")
    
    def get_tests_directory(self):
        """获取测试目录
        
        Returns:
            str: 测试目录路径
        """
        if not self.current_project_path:
            return None
        return os.path.join(self.current_project_path, "tests")
    
    def _create_project_structure(self, project_path):
        """创建项目结构
        
        Args:
            project_path: 项目路径
        """
        # 创建项目目录结构
        for dir_name, sub_dirs in self.DEFAULT_PROJECT_STRUCTURE.items():
            # 创建主目录
            dir_path = os.path.join(project_path, dir_name)
            os.makedirs(dir_path)
            
            # 创建子目录
            for sub_dir in sub_dirs:
                sub_dir_path = os.path.join(dir_path, sub_dir)
                os.makedirs(sub_dir_path)
        
        # 创建.gitignore文件
        gitignore_path = os.path.join(project_path, ".gitignore")
        with open(gitignore_path, "w", encoding="utf-8") as f:
            f.write("# Python\n")
            f.write("__pycache__/\n")
            f.write("*.py[cod]\n")
            f.write("*$py.class\n")
            f.write("\n# Virtual environments\n")
            f.write("venv/\n")
            f.write("env/\n")
            f.write("*.venv\n")
            f.write("\n# IDEs and editors\n")
            f.write(".idea/\n")
            f.write(".vscode/\n")
            f.write("*.swp\n")
            f.write("*.swo\n")
            f.write("*~
")
            f.write("\n# OS generated files\n")
            f.write(".DS_Store\n")
            f.write("Thumbs.db\n")
            f.write("\n# Build files\n")
            f.write("build/\n")
            f.write("dist/\n")
            f.write("*.egg-info/\n")
            f.write("\n# Logs\n")
            f.write("*.log\n")
    
    def _create_project_config(self, project_name, project_path):
        """创建项目配置
        
        Args:
            project_name: 项目名称
            project_path: 项目路径
            
        Returns:
            dict: 项目配置
        """
        return {
            "name": project_name,
            "path": project_path,
            "created_at": datetime.now().isoformat(),
            "last_modified": datetime.now().isoformat(),
            "version": "1.0",
            "author": "",
            "description": "",
            "settings": {
                "editor": {
                    "font_size": 12,
                    "theme": "default",
                    "tab_size": 4,
                    "auto_indent": True,
                    "line_numbers": True,
                    "word_wrap": False
                },
                "designer": {
                    "grid_size": 10,
                    "show_grid": True,
                    "snap_to_grid": True
                },
                "build": {
                    "output_dir": "dist",
                    "build_command": "python setup.py build",
                    "requirements_file": "requirements.txt"
                }
            },
            "files": []
        }
    
    def _save_project_config(self, project_path, project_config):
        """保存项目配置
        
        Args:
            project_path: 项目路径
            project_config: 项目配置
        """
        config_file_path = os.path.join(project_path, self.PROJECT_CONFIG_FILE)
        
        with open(config_file_path, "w", encoding="utf-8") as f:
            json.dump(project_config, f, indent=4, ensure_ascii=False)
    
    def _load_project_config(self, config_file_path):
        """加载项目配置
        
        Args:
            config_file_path: 配置文件路径
            
        Returns:
            dict: 项目配置
        """
        with open(config_file_path, "r", encoding="utf-8") as f:
            return json.load(f)
    
    def update_project_config(self, config_updates):
        """更新项目配置
        
        Args:
            config_updates: 配置更新字典
            
        Returns:
            bool: 是否更新成功
        """
        try:
            # 检查是否有打开的项目
            if not self.current_project_config:
                self.logger.error("没有打开的项目")
                return False, "没有打开的项目"
            
            # 更新配置
            self._deep_update(self.current_project_config, config_updates)
            
            # 保存配置
            return self.save_project()
        except Exception as e:
            self.logger.error(f"更新项目配置失败: {str(e)}")
            return False, f"更新项目配置失败: {str(e)}"
    
    def _deep_update(self, original, updates):
        """深度更新字典
        
        Args:
            original: 原始字典
            updates: 要更新的字典
        """
        for key, value in updates.items():
            if isinstance(value, dict) and key in original and isinstance(original[key], dict):
                self._deep_update(original[key], value)
            else:
                original[key] = value
    
    def add_file_to_project(self, file_path):
        """添加文件到项目
        
        Args:
            file_path: 文件路径
            
        Returns:
            bool: 是否添加成功
        """
        try:
            # 检查是否有打开的项目
            if not self.current_project_path or not self.current_project_config:
                self.logger.error("没有打开的项目")
                return False, "没有打开的项目"
            
            # 检查文件是否存在
            if not os.path.exists(file_path):
                self.logger.error(f"文件 '{file_path}' 不存在")
                return False, "文件不存在"
            
            # 获取文件相对于项目根目录的路径
            rel_file_path = os.path.relpath(file_path, self.current_project_path)
            
            # 检查文件是否已经在项目中
            if "files" not in self.current_project_config:
                self.current_project_config["files"] = []
            
            if rel_file_path not in self.current_project_config["files"]:
                self.current_project_config["files"].append(rel_file_path)
                
                # 保存项目配置
                self.save_project()
                
                self.logger.info(f"文件 '{rel_file_path}' 添加到项目")
            
            return True, rel_file_path
        except Exception as e:
            self.logger.error(f"添加文件到项目失败: {str(e)}")
            return False, f"添加文件到项目失败: {str(e)}"
    
    def remove_file_from_project(self, file_path):
        """从项目中移除文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            bool: 是否移除成功
        """
        try:
            # 检查是否有打开的项目
            if not self.current_project_path or not self.current_project_config:
                self.logger.error("没有打开的项目")
                return False, "没有打开的项目"
            
            # 获取文件相对于项目根目录的路径
            rel_file_path = os.path.relpath(file_path, self.current_project_path)
            
            # 检查文件是否在项目中
            if "files" in self.current_project_config and rel_file_path in self.current_project_config["files"]:
                self.current_project_config["files"].remove(rel_file_path)
                
                # 保存项目配置
                self.save_project()
                
                self.logger.info(f"文件 '{rel_file_path}' 从项目中移除")
            
            return True, rel_file_path
        except Exception as e:
            self.logger.error(f"从项目中移除文件失败: {str(e)}")
            return False, f"从项目中移除文件失败: {str(e)}"
    
    def export_project(self, export_path, export_format="zip"):
        """导出项目
        
        Args:
            export_path: 导出路径
            export_format: 导出格式
            
        Returns:
            bool: 是否导出成功
        """
        try:
            # 检查是否有打开的项目
            if not self.current_project_path:
                self.logger.error("没有打开的项目")
                return False, "没有打开的项目"
            
            # 根据导出格式执行导出
            if export_format.lower() == "zip":
                # 确保导出路径的扩展名是.zip
                if not export_path.endswith(".zip"):
                    export_path += ".zip"
                
                # 创建ZIP文件
                import zipfile
                
                with zipfile.ZipFile(export_path, "w", zipfile.ZIP_DEFLATED) as zipf:
                    # 遍历项目目录中的所有文件和文件夹
                    for root, _, files in os.walk(self.current_project_path):
                        for file in files:
                            # 获取文件的完整路径
                            file_path = os.path.join(root, file)
                            
                            # 获取文件相对于项目根目录的路径
                            rel_path = os.path.relpath(file_path, self.current_project_path)
                            
                            # 添加文件到ZIP文件
                            zipf.write(file_path, rel_path)
            elif export_format.lower() == "folder":
                # 复制项目到目标路径
                if os.path.exists(export_path):
                    shutil.rmtree(export_path)
                
                shutil.copytree(self.current_project_path, export_path)
            else:
                self.logger.error(f"不支持的导出格式: {export_format}")
                return False, f"不支持的导出格式: {export_format}"
            
            self.logger.info(f"项目导出成功到 '{export_path}'")
            return True, export_path
        except Exception as e:
            self.logger.error(f"导出项目失败: {str(e)}")
            return False, f"导出项目失败: {str(e)}"